package com.asp.alumnisystem.base;

import java.lang.ref.WeakReference;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;

/**
 * BasePresenter （mvp中的p）
 *
 * T， E 作为rxjava中传递的参数，不能为空。
 *
 */
public abstract class BasePresenter<T, E>{

    protected Disposable disposable;
    private WeakReference<IView> iView;
    private int type = Integer.MIN_VALUE;

    public BasePresenter(IView view){
        iView = new WeakReference<>(view);
    }

    public void setType(int type) {
        this.type = type;
    }

    public int getType() {
        return type;
    }

    /**
     * 开始工作
     * @param t
     */
    public void work(T t){
        cancel();
        if (iView.get() != null){
            iView.get().loadStart(BasePresenter.this);
        }
        disposable = createRequest(t);
    }


    /**
     * 发起请求审请
     */
    protected Disposable createRequest(T t){
        Observable<BaseBean<E>> observable;
        final Observable<BaseBean<E>> flatObservable = requestNet(t);
        if (flatObservable == null){
            observable = Observable.just(t)
                    .filter(new Predicate<T>() {
                        @Override
                        public boolean test(T t) throws Exception {
                            return filter(t);
                        }
                    })
                    .map(new Function<T, BaseBean<E>>() {
                        @Override
                        public BaseBean<E> apply(T t) throws Exception {
                            Thread.sleep(1000);
                            return BaseBean.requestSuccess(request(t));
                        }
                    });
        }else{
            observable = Observable.just(t)
                    .filter(new Predicate<T>() {
                        @Override
                        public boolean test(T t) throws Exception {
                            return filter(t);
                        }
                    })
                    .flatMap(new Function<T, Observable<BaseBean<E>>>() {
                        @Override
                        public Observable<BaseBean<E>> apply(T t) throws Exception {
                            return flatObservable;
                        }
                    });
        }
        return observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<BaseBean<E>>() {
                    @Override
                    public void accept(BaseBean<E> e) {
                        success(e);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) {
                        throwable.printStackTrace();
                        fail(throwable.getMessage());
                    }
                });
    }

    protected boolean filter(T t){
        return true;
    }

    /**
     * 真正执行请求。子类实现
     */
    protected E request(T t) throws Exception{
        return null;
    }

    /**
     * 真正执行请求。子类实现
     */
    protected Observable<BaseBean<E>> requestNet(T t){
        return null;
    }


    protected void success(BaseBean<E> baseBean){
        if (iView.get() != null){
            iView.get().loadSuccess(this, baseBean);
            iView.get().loadDone(this);
        }
    }

    /**
     *  回调给子类执行失败！
     * @param errorMsg 失败信息
     */
    protected void fail(String errorMsg){
        if (iView.get() != null){
            iView.get().loadSuccess(this, BaseBean.requestFail(errorMsg));
            iView.get().loadDone(this);
        }
    }

    //取消
    public void cancel(){
        if (disposable != null && !disposable.isDisposed()){
            disposable.dispose();
        }
    }

    //销毁
    public void destroy(){
        cancel();
        if (iView != null){
            if (iView.get() != null){
                iView.get().loadDone(this);
            }
            iView.clear();
            iView = null;
        }
    }

}
